#ifndef __LOOPER_HPP__
#define __LOOPER_HPP__

#include <thread>
#include <mutex>
#include <atomic>
#include <thread>
#include <condition_variable>
#include <functional>
#include "Buffer.hpp"

namespace Logs
{
    enum class AsyncType
    {
        ASYNC_SAFE, // 安全状态，表示缓冲区满了则阻塞，避免资源耗尽的风险。
        ASYNC_UNSAFE // 不安全状态，表示缓冲区满了就扩容，无线扩容，常用于测试。
    };
    class AsyncLooper
    {
    public:
        using Functor = std::function<void (Buffer&)>;
        using Ptr = std::shared_ptr<AsyncLooper>;
        AsyncLooper(Functor cb,AsyncType type = AsyncType::ASYNC_SAFE)
            :_callback(cb)
            ,_thread(&AsyncLooper::threadEntry,this)
            ,_stop(false)
            ,_looper_type(type)
        {}
        ~AsyncLooper()
        {
            stop();
        }
        void push(const char* str,size_t len)
        {
            // // 1.安全的————不扩容。
            // if(_type == AsyncType::ASYNC_SAFE)
            // {
            //     ;
            // }
            // // 2.不安全————扩容
            // if(_type == AsyncType::ASYNC_UNSAFE)
            // {
            //     ;
            // }
            std::unique_lock<std::mutex> lock(_mutex);
            // 安全的才可能会阻塞。
            // 避免扩容。
            if(_stop == true)
            {
                return ;
            }
            if(_looper_type == AsyncType::ASYNC_SAFE)
                _cond_con.wait(lock,[&](){ return _pro_buf.writeAbleLen() >= len; });
            // 走到下面这一步，说明满足条件，可以添加数据
            _pro_buf.push(str,len);
            // 唤醒消费者进行处理。
            _cond_pro.notify_all();
        }
        void stop()
        {
            _stop = true;
            // 所有生产者写入线程都停止。
            // 唤醒所有工作线程。
            _cond_con.notify_all();
            // 由进程来回收。
            _thread.join();
        }
    private:
        Functor _callback;// 处理缓冲区的函数。其实就是落地到哪个部分。
    private:
        void threadEntry()
        {
            while(1)
            {
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    // 为空则阻塞。不为空就交换。
                    if(_stop && _pro_buf.empty()) return ;
                    // 条件二是阻塞的条件,当日志正在运行时需要处理的缓冲区为空，。
                    // 如果日志不在运行没必要再等待了，直接将缓冲区的内容放进去就行了。
                    _cond_pro.wait(lock,[&](){ return !_pro_buf.empty() || _stop; });
                    _con_buf.swap(_pro_buf);
                    _cond_con.notify_all();
                }
                _callback(_con_buf);
                _con_buf.reset();
            }
        }
    private:
        std::atomic<bool> _stop;
        AsyncType _looper_type;
        Buffer _con_buf; // 消费者缓冲区。
        Buffer _pro_buf; // 生产者缓冲区。
        std::mutex _mutex;
        std::thread _thread;
        std::condition_variable _cond_con; // 生产者条件变量。
        std::condition_variable _cond_pro; // 消费者条件变量。
    };
}

#endif